/* 
 * [New BSD License (BSD 3-Clause License)]
 * Copyright (c) 2012, Max Bechtold
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 *     - Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     - Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     - Neither the name of the Rel2Xml Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package maxbe.rel2xml.generator.docs.constraints;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import maxbe.rel2xml.generator.Column;
import maxbe.rel2xml.generator.docs.DataType;

/**
 * This class merely servers as a mean to convey the source column the values
 * are derived from and does not generate values itself. It is comparable to
 * {@link References} but has somewhat different semantics.<br/>
 * Columns can only be derived from columns with a dependency relationship
 * between the derivating column's table and the source column's table. Plus, if
 * a column does not derive from its own table, the filling factors in the
 * hierarchy to the source column's table must not vary (like '[5..10] per').
 * 
 * @author Max Bechtold
 * 
 */
public class DerivedValues implements ValueConstructor {

	/** Column that the values are taken from */
	private final Column sourceColumn;

	/** List of values of sourceColumn */
	private List<String> sourceVals;

	/** Supporting variables */
	private Iterator<String> it;
	private String currentVal;
	private int currentIndex = 0;

	/**
	 * States whether the values are derived from a column of the same table ->
	 * special handling as the mark method is only invoked for every new tuple
	 * of tables in the dependency chain
	 */
	private boolean local;

	public DerivedValues(Column sourceColumn) {
		this.sourceColumn = sourceColumn;
	}

	public boolean isLocal() {
		return local;
	}

	public Column getSourceColumn() {
		return sourceColumn;
	}

	public void setLocal(boolean local) {
		this.local = local;
	}

	public void setSourceVals(List<String> sourceVals) {
		this.sourceVals = sourceVals;
		it = sourceVals.iterator();
	}

	@Override
	public void announce(int number) {
		if (sourceVals == null) {
			sourceVals = sourceColumn.prepareValues();
			it = sourceVals.iterator();
		}
	}

	@Override
	public int getLength() {
		return -1;
	}

	@Override
	public int getSubLength() {
		return -1;
	}

	@Override
	public boolean lengthVaries() {
		return false;
	}

	@Override
	public void mark(int number) {
		if (!local) {
			if (!it.hasNext()) {
				it = sourceVals.iterator();
			}
			currentVal = it.next();
		}
	}

	@Override
	public boolean needsAnnounce() {
		return true;
	}

	@Override
	public String next() {
		if (local)
			return sourceVals.get(currentIndex++);
		else
			return currentVal;

	}

	@Override
	public List<String> next(int number) {
		if (local) {
			currentIndex = currentIndex + number;
			return sourceVals.subList(currentIndex - number, currentIndex);
		} else {
			return Collections.nCopies(number, currentVal);
		}
	}

	@Override
	public String toString() {
		return "derived from " + sourceColumn.getTable().getName() + "."
				+ sourceColumn.getName();
	}

	@Override
	public List<DataType> getSupportedDataTypes() {
		return null;
	}

}
